package kgame5.kengine {
import kgame5.kengine.events.SendCommandEvent;
import kgame5.kengine.gameunit.GameUnit;

import flash.display.Sprite;
import flash.events.Event;
import flash.utils.Dictionary;

/**
 * @author kk
 * 保持gameWorld:Proxy
 * 保持GameCommand:Command
 * 保持视图:View?
 * 提供稳定帧频
 * 
 * --
 * 缺陷是，摄像机还没有作为一个GameUnit加入到体系中。它算是一个GameActor,有自己的FSM
 */
public class GamePlay {
	
	protected var gameWorld:GameWorld;//逻辑游戏世界，持有各个GameUnit,并执行更新
	
	protected var viewComp:GameView;
	
	private var mc:Sprite;//只是用来装载efh用的,装载3d视图的
	//一个保证逻辑帧频，保证不会因为低帧频而丢掉逻辑update()
	private var loop:GameLoop;
	
	private var dict_commands:Dictionary;//dict[commandName]=GameCommand
	
	public function GamePlay(w:int,h:int,frameRate:int=20,bDebug:Boolean=true){
		
		gameWorld=new GameWorld();
		
		viewComp=new GameView(w,h,bDebug);
		
		mc=new Sprite();
		mc.addChild(viewComp.view3D.getDO());

		//
		loop=new GameLoop(frameRate);
		
		//注册命令 
		dict_commands=new Dictionary();

		doInitCommands();//注册各个命令，注意需要被子类继承
	}
	
	public function getDO():Sprite{
		return mc;
	}
	
	public function getView():GameView{
		return viewComp;
	}
	
	public function getWorld():GameWorld{
		return gameWorld;
	}
	
	//模板函数，初始化全部命令
	protected function doInitCommands():void{
		//registerCommand(ssss)
		//registerCommand(xxx);
		//...
	}
	
	//注册各个commands,被子类使用
	protected function registerCommand(commandName:String,cmd:GameCommand):void{
		dict_commands[commandName]=cmd;
		cmd.setGamePlay(this);
		cmd.addEventListener(SendCommandEvent.TYPE, onSendCommandEvent);
	}
	
	//这个被其他调用,注意需要被子类继承
	public function startup(data:Object):void{
		
		gameWorld.init();
		
		viewComp.start();
		//view3D.camera.init~//TODO 这里还没做好设置摄像机的工作
		
		loop.start();
		mc.addEventListener(Event.ENTER_FRAME, efh);//efh
	}
	
	public function clear():void{
		
		gameWorld.clear();
		
		viewComp.clear();
		
		//efh
		mc.removeEventListener(Event.ENTER_FRAME, efh);
		//loop.clear();//loop不需要clear()
	}
	
	//主要是会被command调用吧
	public function addGameUnit(gu:GameUnit):void{
		gameWorld.addChild(gu);
		viewComp.addChild(gu.getView().getMD(), gu.getView().getMD().layerID);
		gu.addEventListener(SendCommandEvent.TYPE, onSendCommandEvent);
	}
	
	public function removeGameUnit(gu:GameUnit):void{
		gameWorld.removeChild(gu.getID());
		viewComp.removeChild(gu.getView().getMD());
	}
	
	private function onSendCommandEvent(e:SendCommandEvent):void{
		executeCommand(e.getCommandName(),e.getData());
	}
	
	protected function executeCommand(commandName:String,data:Object):void{
		var gc:GameCommand=dict_commands[commandName] as GameCommand;
		if(gc!=null){
			gc.execute(data);
		}
	}
	
	private function efh(e:Event):void {
		//1,计算丢失的帧
		var lostCount:int=loop.lostFrameCount();
		//2,补上丢失的帧
		for(var i:int=0;i<lostCount;i++){
			this.realUpdate();
		}
	}
	
	//被gameLoop通知执行真正的逻辑
	private function realUpdate():void{
		gameWorld.update();
		viewComp.update();
	}
}
}
